package p.ithorns.integration.zk.confcenter;

import lombok.extern.slf4j.Slf4j;
import org.apache.zookeeper.AsyncCallback;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * ZkConfWatcher
 * Zk 模拟配置中心
 *
 * @author ithorns
 * @version 1.0
 * @date 2019/9/21 22:30
 */
@Slf4j
public class ZkConfWatcher implements Watcher,
        AsyncCallback.StatCallback,
        AsyncCallback.DataCallback,
        AsyncCallback.ChildrenCallback {

    private ZooKeeper zk;

    private Object ctx;

    private CountDownLatch cdl = new CountDownLatch(1);

    public void setZk(ZooKeeper zk) {
        this.zk = zk;
    }

    @Override
    public void process(WatchedEvent event) {
        log.info("ZkConfWatcher ===========> event: {}", event.toString());
        Event.EventType type = event.getType();
        switch (type) {
            case NodeCreated:
            case NodeDataChanged:
                zk.getData(event.getPath(), this, this, this.ctx);
                break;
            case NodeDeleted:
                break;
            case NodeChildrenChanged:
            case None:
            default:  break;
        }
    }

    /**
     * 状态事件回调
     *
     * @param rc, path, ctx, stat
     * @author 2019/9/21-22:31 by Ht.L
     */
    @Override
    public void processResult(int rc, String path, Object ctx, Stat stat) {
        log.info("StatCallback ===========> rc:[{}], path:[{}], stat:[{}]", rc, path, stat);
        this.ctx = ctx;
        // 如果stat不为null，说明节点已经存在，可以在DataCallbacka取数据
        if (stat != null) {
            try {
                zk.getData(path, this, this, ctx);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 数据事件回调
     *
     * @param rc, path, ctx, data, stat
     * @author 2019/9/21-22:31 by Ht.L
     */
    @Override
    public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat) {
        try {
            if (data != null) {
                String dataStr = new String(data);
                log.info("DataCallback ===========> rc:[{}], path:[{}], data:[{}]", rc, path, dataStr);
                //cdl.countDown();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void await() throws InterruptedException {
        zk.exists("/AppConf", this, this, "ZKCONF");
        cdl.await();
    }

    /**
     * 子节点事件回调
     * @author 2019/9/21-23:22 by Ht.L
     * @param rc, path, ctx, children
     */
    @Override
    public void processResult(int rc, String path, Object ctx, List<String> children) {
        Collections.sort(children);
        int index = children.indexOf(path);
        if (index == 0) {
            // 如果是第一个节点
            // 获取锁
            // 执行业务
            // 释放锁
        } else {
            // watch 上一个节点
        }
    }
}
